package event

import (
	"context"
	"log/slog"
	"runtime"
	"strings"
	"sync"
	"time"
)

type EventData map[string]any
type EventHandler func(data EventData) error
type EventBusIO interface {
	// Subscribe 异步方式订阅事件(长期订阅)
	//  - eventName 事件名称
	//  - eventHandler 回调函数
	Subscribe(eventName string, eventHandler EventHandler) error
	// SubscribeOnce 异步方式订阅事件(仅订阅一次)
	//  - eventName 事件名称
	//  - eventHandler 回调函数
	SubscribeOnce(eventName string, eventHandler EventHandler) error
	// SubscribeSync 同步方式订阅事件(长期订阅)
	//  - eventName 事件名称
	//  - eventHandler 回调函数
	SubscribeSync(eventName string, eventHandler EventHandler) error
	// SubscribeSyncOnce 同步方式订阅事件(仅订阅一次)
	//  - eventName 事件名称
	//  - eventHandler 回调函数
	SubscribeSyncOnce(eventName string, eventHandler EventHandler) error
	// Unsubscribe 取消订阅事件
	//  - eventName 事件名称
	//  - eventHandler 回调函数(订阅事件时的同一个回调函数)
	Unsubscribe(eventName string, eventHandler EventHandler) error
	// Publish 发布事件, 触发事件广播
	//   - eventName 事件名称
	//   - data 事件参数 无参数时为nil
	Publish(eventName string, data EventData) error
	// Name 获取EventBus的名称
	Name() string
	// State 获取EventBus的状态
	State() bool
	// Disabled 禁用EventBus
	Disabled()
	// Enabled 启用EventBus
	Enabled()
	// GetEvents 获取EventBus的全部事件订阅信息
	GetEvents() EventsInfo
	// EventState 获取某一个事件的状态
	//   - eventName 事件名称
	StateEvent(eventName string) bool
	// EventDisable 禁用某一个事件
	//   - eventName 事件名称
	DisabledEvent(eventName string) error
	// EventEnabled 启用某一个事件
	//   - eventName 事件名称
	EnabledEvent(eventName string) error
}
type eventBus struct {
	name          string // 事件总线的名称
	state         bool   // 事件总线的状态
	dispatchs     []*eventDispatch
	isGlobal      bool // 是否是全局事件总线
	ctxBackground context.Context
	mu            sync.RWMutex
}
type EventsInfo struct {
	Count  int            // 全部事件订阅总数量(异步+同步)
	Events map[string]int // 事件名=>订阅总数量(异步+同步)
}

const (
	shardCount       uint   = 32
	shardHashFnv32   uint32 = 2166136261
	shardHashPrime32 uint32 = 16777619
)

// NewEventBus 创建一个事件总线
func NewEventBus(name string) EventBusIO {
	name = strings.TrimSpace(name)
	if name == "" {
		panic("NewEventBus, The name cannot be empty")
	}
	bus := new(eventBus)
	bus.name = name
	bus.state = true
	bus.dispatchs = make([]*eventDispatch, shardCount)
	bus.ctxBackground = context.Background()
	var i uint = 0
	for ; i < shardCount; i++ {
		bus.dispatchs[i] = newEventDispatch(bus)
	}
	return bus
}

// shardHash FNV32 hash
func shardHash(key string) uint {
	hash := shardHashFnv32
	for i := 0; i < len(key); i++ {
		hash *= shardHashPrime32
		hash ^= uint32(key[i])
	}
	return uint(hash)
}

// Subscribe 异步方式订阅事件(长期订阅)
//   - eventName 事件名称
//   - eventHandler 回调函数
func (e *eventBus) Subscribe(eventName string, eventHandler EventHandler) error {
	eventName = strings.TrimSpace(eventName)
	if eventName == "" {
		e.log(e.getEntryPC(3), slog.LevelWarn, "Subscribe, eventName cannot be empty")
		return ErrEventName
	}
	if eventHandler == nil {
		e.log(e.getEntryPC(3), slog.LevelWarn, "Subscribe["+eventName+"], eventHandler cannot be empty")
		return ErrEventHandler
	}
	e.mu.RLock()
	defer e.mu.RUnlock()
	if !e.state {
		// 禁用状态的事件总线，忽略事件订阅
		return ErrBusDisable
	}
	return e.dispatchs[shardHash(eventName)%shardCount].subscribe(eventName, eventHandler)
}

// SubscribeOnce 异步方式订阅事件(仅订阅一次)
//   - eventName 事件名称
//   - eventHandler 回调函数
func (e *eventBus) SubscribeOnce(eventName string, eventHandler EventHandler) error {
	eventName = strings.TrimSpace(eventName)
	if eventName == "" {
		e.log(e.getEntryPC(3), slog.LevelWarn, "SubscribeOnce, eventName cannot be empty")
		return ErrEventName
	}
	if eventHandler == nil {
		e.log(e.getEntryPC(3), slog.LevelWarn, "SubscribeOnce["+eventName+"], eventHandler cannot be empty")
		return ErrEventHandler
	}
	e.mu.RLock()
	defer e.mu.RUnlock()
	if !e.state {
		// 禁用状态的事件总线，忽略事件订阅
		return ErrBusDisable
	}
	return e.dispatchs[shardHash(eventName)%shardCount].subscribeOnce(eventName, eventHandler)
}

// SubscribeSync 同步方式订阅事件(长期订阅)
//   - eventName 事件名称
//   - eventHandler 回调函数
func (e *eventBus) SubscribeSync(eventName string, eventHandler EventHandler) error {
	eventName = strings.TrimSpace(eventName)
	if eventName == "" {
		e.log(e.getEntryPC(3), slog.LevelWarn, "SubscribeSync, eventName cannot be empty")
		return ErrEventName
	}
	if eventHandler == nil {
		e.log(e.getEntryPC(3), slog.LevelWarn, "SubscribeSync["+eventName+"], eventHandler cannot be empty")
		return ErrEventHandler
	}
	e.mu.RLock()
	defer e.mu.RUnlock()
	if !e.state {
		// 禁用状态的事件总线，忽略事件订阅
		return ErrBusDisable
	}
	return e.dispatchs[shardHash(eventName)%shardCount].subscribeSync(eventName, eventHandler)
}

// SubscribeSyncOnce 同步方式订阅事件(仅订阅一次)
//   - eventName 事件名称
//   - eventHandler 回调函数
func (e *eventBus) SubscribeSyncOnce(eventName string, eventHandler EventHandler) error {
	eventName = strings.TrimSpace(eventName)
	if eventName == "" {
		e.log(e.getEntryPC(3), slog.LevelWarn, "SubscribeSyncOnce, eventName cannot be empty")
		return ErrEventName
	}
	if eventHandler == nil {
		e.log(e.getEntryPC(3), slog.LevelWarn, "SubscribeSyncOnce["+eventName+"], eventHandler cannot be empty")
		return ErrEventHandler
	}
	e.mu.RLock()
	defer e.mu.RUnlock()
	if !e.state {
		// 禁用状态的事件总线，忽略事件订阅
		return ErrBusDisable
	}
	return e.dispatchs[shardHash(eventName)%shardCount].subscribeSyncOnce(eventName, eventHandler)
}

// Unsubscribe 取消订阅事件
//   - eventName 事件名称
//   - eventHandler 回调函数(订阅事件时的同一个回调函数)
func (e *eventBus) Unsubscribe(eventName string, eventHandler EventHandler) error {
	eventName = strings.TrimSpace(eventName)
	if eventName == "" {
		e.log(e.getEntryPC(3), slog.LevelWarn, "Unsubscribe, eventName cannot be empty")
		return ErrEventName
	}
	if eventHandler == nil {
		e.log(e.getEntryPC(3), slog.LevelWarn, "Unsubscribe["+eventName+"], eventHandler cannot be empty")
		return ErrEventHandler
	}
	e.mu.RLock()
	defer e.mu.RUnlock()
	return e.dispatchs[shardHash(eventName)%shardCount].unsubscribe(eventName, eventHandler)
}

// Publish 发布事件, 触发事件广播
//   - eventName 事件名称
//   - eventData 事件参数
func (e *eventBus) Publish(eventName string, eventData EventData) error {
	eventName = strings.TrimSpace(eventName)
	if eventName == "" {
		e.log(e.getEntryPC(3), slog.LevelWarn, "Publish, eventName cannot be empty")
		return ErrEventName
	}
	e.mu.RLock()
	defer e.mu.RUnlock()
	if !e.state {
		// 禁用状态的事件总线，忽略事件订阅
		return ErrBusDisable
	}
	return e.dispatchs[shardHash(eventName)%shardCount].publish(eventName, eventData)
}

// Name 获取事件总线的名称
func (e *eventBus) Name() string {
	return e.name
}

// GetEvents 获取事件总线的全部事件信息
func (e *eventBus) GetEvents() (info EventsInfo) {
	e.mu.Lock()
	defer e.mu.Unlock()
	info = EventsInfo{Count: 0, Events: make(map[string]int)}
	for _, dispatch := range e.dispatchs {
		v := dispatch.getEvents()
		info.Count += v.Count
		for eventName, count := range v.Events {
			if _, ok := info.Events[eventName]; !ok {
				info.Events[eventName] = count
			} else {
				info.Events[eventName] += count
			}
		}
	}
	return
}

// State 获取EventBus的状态
func (e *eventBus) State() bool {
	e.mu.RLock()
	defer e.mu.RUnlock()
	return e.state
}

// Disabled 禁用EventBus
func (e *eventBus) Disabled() {
	e.mu.Lock()
	defer e.mu.Unlock()
	e.state = false
}

// Enabled 启用EventBus
func (e *eventBus) Enabled() {
	e.mu.Lock()
	defer e.mu.Unlock()
	e.state = true
}

// StateEvent 获取某一个事件的状态
//   - eventName 事件名称
func (e *eventBus) StateEvent(eventName string) bool {
	eventName = strings.TrimSpace(eventName)
	if eventName == "" {
		e.log(e.getEntryPC(3), slog.LevelWarn, "StateEvent, eventName cannot be empty")
		return false
	}
	return e.dispatchs[shardHash(eventName)%shardCount].state(eventName)
}

// DisabledEvent 禁用某一个事件
//   - eventName 事件名称
func (e *eventBus) DisabledEvent(eventName string) error {
	eventName = strings.TrimSpace(eventName)
	if eventName == "" {
		e.log(e.getEntryPC(3), slog.LevelWarn, "DisabledEvent, eventName cannot be empty")
		return ErrEventName
	}
	return e.dispatchs[shardHash(eventName)%shardCount].disabled(eventName)
}

// EnabledEvent 启用某一个事件
//   - eventName 事件名称
func (e *eventBus) EnabledEvent(eventName string) error {
	eventName = strings.TrimSpace(eventName)
	if eventName == "" {
		e.log(e.getEntryPC(3), slog.LevelWarn, "EnabledEvent, eventName cannot be empty")
		return ErrEventName
	}
	return e.dispatchs[shardHash(eventName)%shardCount].enabled(eventName)
}

// getEntryPC 获取EventBus 的调用栈入口PC
func (e *eventBus) getEntryPC(skip int) uintptr {
	// !internal.IgnorePC =>TRUE
	var pcs [1]uintptr
	// skip [runtime.Callers, this function, this function's caller]
	if e.isGlobal {
		runtime.Callers(skip+1, pcs[:])
	} else {
		runtime.Callers(skip, pcs[:])
	}
	return pcs[0]
}

// log 日志记录写入, 支持自定义 slog.Record.PC
func (e *eventBus) log(pc uintptr, level slog.Level, msg string, args ...any) {
	if !GetLogger().Handler().Enabled(e.ctxBackground, level) {
		return
	}
	args = append(args, slog.String("fromEventBus", e.name))
	if pc == 0 {
		GetLogger().Log(e.ctxBackground, level, msg, args...)
		return
	}
	record := slog.NewRecord(time.Now(), level, msg, pc)
	record.Add(args...)
	GetLogger().Handler().Handle(e.ctxBackground, record)
}

// logAttrs 日志记录写入, 支持自定义 slog.Record.PC
func (e *eventBus) logAttrs(pc uintptr, level slog.Level, msg string, attrs ...slog.Attr) {
	if !GetLogger().Handler().Enabled(e.ctxBackground, level) {
		return
	}
	attrs = append(attrs, slog.String("fromEventBus", e.name))
	if pc == 0 {
		GetLogger().LogAttrs(e.ctxBackground, level, msg, attrs...)
		return
	}
	record := slog.NewRecord(time.Now(), level, msg, pc)
	record.AddAttrs(attrs...)
	GetLogger().Handler().Handle(e.ctxBackground, record)
}
